#ifndef __MY_UTIL__
#define __MY_UTIL__


#include "bundle.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sys/stat.h>
#include <experimental/filesystem>
#include <jsoncpp/json/json.h>

namespace cloud{
    namespace fs = std::experimental::filesystem;
    class FileUtil{
        public:
            FileUtil(const std::string& filename):_filename(filename)
            {}
            //文件大小
            bool Remove(){
                if(this->Exists() == false){
                    return true;
                }
                remove(_filename.c_str());
                return true;
            }
            int64_t FileSize(){
                struct stat st;
                if(stat(_filename.c_str(), &st) < 0){
                    std::cout << "get file size failed\n";
                    return -1;
                }
                return st.st_size;
            }
            //最后一次修改时间
            time_t LastMTime(){
                struct stat st;
                if(stat(_filename.c_str(), &st) < 0){
                    std::cout << "get last modify failed\n";
                    return -1;
                }
                return st.st_mtime;
            }
            //最后一次访问时间
            time_t LastATime(){
                struct stat st;
                if(stat(_filename.c_str(), &st) < 0){
                    std::cout << "get last access time failed!\n";
                    return -1;
                }
                return st.st_atime;
            }
            std::string Filename(){
                // ./abc/test.txt 找到最后一个斜杆，之后内容就是文件名
                size_t pos = _filename.find_last_of("/");
                if(pos == std::string::npos){
                    return _filename;
                }
                return _filename.substr(pos+1);
            }
            bool GetPosLen(std::string* body, size_t pos, size_t len){
                //判断传入的数据大小是否超过了文件数据大小
                size_t fsize = this->FileSize();
                if(pos + len > fsize){
                    std::cout << "get file len error!\n";
                    return false;
                }
                //打开文件进行读取
                std::ifstream ifs;
                ifs.open(_filename, std::ios::binary);
                if(ifs.is_open() == false){
                    std::cout << "read open file error!\n";
                    return false;
                }
                ifs.seekg(pos, std::ios::beg);//跳转到pos位置
                body->resize(len);
                ifs.read(&(*body)[0], len);//将数据读取之后放入到body中
                if(ifs.good() == false){
                    std::cout << "get file content error!\n";
                    ifs.close();
                    return false;
                }
                ifs.close();
                return true;
            }
            bool GetContent(std::string* body){
                size_t fsize = this->FileSize();
                return GetPosLen(body, 0, fsize);
            }
            //将数据写入到文件中
            bool SetContent(const std::string& body){
                std::ofstream ofs;
                ofs.open(_filename, std::ios::binary);
                if(ofs.is_open() == false){
                    std::cout << "write open file error!\n";
                    return false;
                }
                ofs.write(&body[0], body.size());
                if(ofs.good() == false){
                    std::cout << "write file content error!\n";
                    ofs.close();
                    return false;
                }
                ofs.close();
                return true;
            }
            //文件压缩
            bool Compress(const std::string& packname){
                //1.获取文件数据
                std::string body;
                if(this->GetContent(&body) == false){
                    std::cout << "compress get file error!\n";
                    return false;
                }
                //2.对数据进行压缩
                std::string packed = bundle::pack(bundle::LZIP, body);
                //3.将压缩后的数据存储到压缩包文件中
                FileUtil fu(packname);
                if(fu.SetContent(packed) == false){
                    std::cout << "compress write pack error!\n";
                    return false;
                }
                return true;
            }
            //文件解压
            bool UnCompress(const std::string& filename){
               //1.将当前压缩包数据读取出来
               std::string body;
               if(this->GetContent(&body) == false){
                    std::cout << "uncompress get file error!\n";
                    return false;
               }
               //2.对压缩数据进行解压缩
               std::string unpacked = bundle::unpack(body);
               //3.将解压缩后的数据写入到新文件中
               FileUtil fu(filename);
               if(fu.SetContent(unpacked) == false){
                    std::cout << "uncompress write pack error!\n";
                    return false;
               }
               return true;
            }
            //判断文件是否存在
            bool Exists(){
                return fs::exists(_filename);
            }
            //创建目录
            bool CreateDirectory(){
                if(Exists()) return true;
                return fs::create_directories(_filename);
            }
            //扫描目录
            bool ScanDirectory(std::vector<std::string>* arry){
                for(auto& p: fs::directory_iterator(_filename)){
                    if(fs::is_directory(p) == true){
                        continue;
                    }
                    //relative_path 带有路径的文件名
                    arry->push_back(fs::path(p).relative_path().string());
                }
                return true;
            }
        private:
            std::string _filename;
    };

    class JsonUtil{
        public:
            static bool Serialize(const Json::Value& root,  std::string* str){
                Json::StreamWriterBuilder swb;
                std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
                std::stringstream ss;
                if(sw->write(root, &ss) != 0){
                    std::cout << "json write error" << std::endl;
                    return false;
                }
                *str = ss.str();
                return true;
            }
            static bool UnSerialize(const std::string& str, Json::Value* root){
                Json::CharReaderBuilder crb;
                std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
                std::string err;
                bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), root, &err);
                if(ret == false){
                    std::cout << "json parse error" << std::endl;
                    std::cout << err << std::endl;
                    return false;
                }
                return true;
            }
    };
}

#endif